/**
 * 
 */
package org.manggis.xml;

import java.util.Stack;

import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.manggis.io.Resource;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author ppacka
 *
 */
public class DocumentParser extends DefaultHandler {

	private Resource resource;
	private Document doc;
	private Element element;
	private Stack stack;
	private StringBuffer text;
	
	public DocumentParser(Resource resource) {
		this.resource = resource;
		element = new Element("", null);
		doc = new Document(element);
		stack = new Stack();
		text = new StringBuffer();
	}

	public Document parse() {
		try {
			InputSource input = new InputSource(resource);
	        input.setSystemId(resource.getResourceURI());
	        
	        getReader(getParser(getFactory())).parse(input);
	 
			return doc;
		} catch(Exception e) {
			throw new XmlParserException("While document parsing, the error occurred.");
		}
	}

	protected XMLReader getReader(SAXParser parser) throws SAXException {
		XMLReader reader = parser.getXMLReader();
		reader.setDTDHandler(this);
		reader.setContentHandler(this);
		reader.setEntityResolver(this);
		reader.setErrorHandler(this);
		
		return reader;
	}

	protected SAXParser getParser(SAXParserFactory factory) throws ParserConfigurationException, SAXException {
		return factory.newSAXParser();
	}

	protected SAXParserFactory getFactory() throws FactoryConfigurationError {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		//factory.setNamespaceAware(false);
        //factory.setValidating(false);
		
		return factory;
	}
	
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		String name = localName;
    	if ((name == null) || (name.length() < 1)) {
    		name = qName;
    	}
    	
		Element element = new Element(name, stack.empty()? null : (Element)stack.peek());
		
		for (int i = 0; i < attributes.getLength(); i++) {
    		String attribute = attributes.getLocalName(i);
    		if ((attribute == null) || (attribute.length() < 1)) {
    			attribute = attributes.getQName(i);
    		}
    		
    		String value = attributes.getValue(i);
    		element.putAttribute(attribute, value);
    	}
		
		stack.push(element);
	}
	
	public void characters(char[] ch, int start, int length) throws SAXException {
		text.append(ch, start, length);
	}

	public void endElement(String uri, String localName, String qName) throws SAXException {
		stack.pop();
		text.setLength(0);
	}

}
